package ADTs;

import java.awt.Point;

import Project.Main;
/**
 * This class is a data structure of Positions(Points) on the screen.
 * Also this data structure can convert coordinates from actual size 
 * to internal size and backward. 
 * 
 * @author	Brian Wetherbee
 * 			Ryan McNamara
 * 			Zeng Yang
 *
 */
public class PointADT {
	//@ invariant x >= 0 && x <= Constants.width;
	//@ invariant y >= 0 && y <= Constants.height;

	private /*@ spec_public @*/double x = 0, y = 0;

	//Constructor with two double parameters. 
	//@ ensures x == xCoor;
	//@ ensures y == yCoor;
	public PointADT(double xCoor, double yCoor) {
		x = xCoor;
		y = yCoor;
	}

	//Constructor with a Point parameter.
	//@ requires p != null;
	//@ requires p.x >= 0 && p.x <= Constants.width;
	//@ requires p,y >= 0 && p.y <= Constants.height;
	//@ ensures this.x = p.x;
	//@ ensures this.y = p.y;
	public PointADT(Point p){
		this.x = p.x;
		this.y = p.y;
	}

	/* @ requires true; @ */
	//@ requires xCoor >= 0 && xCoor <= Constants.width;
	//@ requires yCoor >= 0 && yCoor <= Constants.height;
	public boolean equal(double xCoor, double yCoor) {
		return (xCoor == x && yCoor == y);
	}
	
	/* @ requires p != null; @ */
	public boolean equal(PointADT p) {
		return (this.equal(p.getX(), p.getY()));
	}

	/*
	 * @ requires xCoor >= 0 && xCoor <= Constants.width;
	 * @ requires yCoor >= 0 && yCoor <= Constants.height;
	 * @ ensures x == xCoor;
	 * @ ensures y == yCoor;
	 * @
	 */
	public void move(double xCoor, double yCoor) {
		x = xCoor;
		y = yCoor;
	}

	public String toString() {
		return "[" + x + "," + y + "]";
	}

	//@ ensures x = x / getMagnitude();
	//@ ensures y = y / getMagnitude();
	public void normalize() {
		double magnitude = getMagnitude();
		x /= magnitude;
		y /= magnitude;
		return;
	}

	//@ requires scalar > 0;
	public void scaleToMagnitude(double scalar) {
		normalize();
		scale(scalar);
	}

	//@ requires scalar > 0;
	//@ ensures x = x * scalar;
	//@ ensures y = y * scalar;
	public void scale(double scalar) {
		x *= scalar;
		y *= scalar;
	}

	//@ requires b != null;
	public double dot(PointADT b) {
		return dot(this, b);
	}

	//To make a copy of current point coordinates x and y;
	public PointADT copy(){
		return new PointADT(x,y);
	}
	
	
	//@ ensures this.x = Main.internalToActualX(this.x);
	//@ ensures this.y = Main.internalToActualY(this.y);
	public void internalToActual(){
		this.x = Main.internalToActualX(this.x);
		this.y = Main.internalToActualY(this.y);
	}

	//@ ensures this.x = this.x = Main.actualToInternalX(this.x);
	//@ ensures this.y = this.y = Main.actualToInternalY(this.y);
	public void actualToInternal(){
		this.x = Main.actualToInternalX(this.x);
		this.y = Main.actualToInternalY(this.y);
	}
	

	// to add to just one component
	//@ requires toAdd + x >= 0 && toAdd + x <= Constants.width;
	//@ ensures this.x == (\old getX() + toAdd);
	public void xAdd(double toAdd) {
		setX(getX() + toAdd);
	}
	
	// to add to just one component);
	//@ requires toAdd + y >= 0 && toAdd + y <= Constants.height;
	//@ ensures this.y == (\old getY() + toAdd);
	public void yAdd(double toAdd) {
		setY(getY() + toAdd);
	}
	
	//@ requires x >= 0  && x <= Contants.width;
	//@ ensures this.x == x;
	public void setX(double x) {
		this.x = x;
	}

	//@ \result == x;
	public double getX() {
		return x;
	}

	//@ requires y >= 0  && y <= Contants.height;
	//@ ensures this.y == y;
	public void setY(double y) {
		this.y = y;
	}

	//@ \result == y;
	public double getY() {
		return y;
	}

	//This is calculate the distance from origin to current point
	//@ ensures \result <= Math.sqrt(Constants.winth * Constants.winth + Constants.height * Constant.height); 
	public double getMagnitude() {
		return Math.sqrt(x * x + y * y);
	}
	
	//****STATIC METHODS*****//
	//@ requires p1 != null && p2 != null;
	/*@ ensures (\forall PointADT p == \result; p.getX() == p1.getX() + p2.getX()
				p.getY() == p1.getY() + p2.getY(); p)@*/
	public static PointADT addPoints(PointADT p1, PointADT p2){
		return new PointADT(p1.getX() + p2.getX(),p1.getY() + p2.getY());
	}
	
	//@ requires a != null;
	//@ requires b != null;
	//@ ensures \result <= Constants.winth * Constants.winth + Constants.height * Constant.height;
	public static double dot(PointADT a, PointADT b) {
		return a.getX() * b.getX() + a.getY() * b.getY();
	}
	
	//To calculate the distance b/w. a and b
	//@ requires a != null;
	//@ requires b != null;
	public static double distance(PointADT a, PointADT b){
		PointADT nega = a.copy();
		nega.scale(-1);
		return addPoints(nega,b).getMagnitude();
	}
	
	

}
